/**接收信息分同步和异步两类
 * 一、同步接收
 * jmsTemplate有下列接收消息方法：
 * 1）Message receive()
 * 2）Message receive(Destination destination)
 * 3）Message receive(String destinationName)
 * 4）Object receiveAndConvert()
 * 5）Object receiveAndConvert(Destination destination)
 * 6）Object receiveAndConvert(String destinationName)
 * 以上所有方法还有一个完全对应的带选择器的接收方法：receiveSelected和receiveSelectedAndConvert
 * jmsMessagingTemplate有下列接收消息方法：
 * 1）Message<?> receive()
 * 2）Message<?> receive(String destinationName)
 * 3）T receiveAndConvert(Class<T> targetClass)
 * 4）T receiveAndConvert(String destinationName, Class<T> targetClass)
 * 二、异步接收
 * 方法一：@JmsListener
 * 1）@EnableJms
 * 2）Spring提供了两个MesssageListenerContainer的实例：SimpleMessageListenerContainer和 DefaultMessageListenerContainer
 * 分别由JmsListenerContainerFactory的实例：SimpleJmsListenerContainerFactory和DefaultJmsListenerContainerFactor来创建对象
 * 后者比前者额外提供：动态调整监听线程的数量和与外部事务（如XA Transactions）集成的功能
 * 3）@JmsListener，在其中通过containerFactory属性来指定使用哪个JmsListenerContainerFactory，不指定则相当于MessageListenerAdapter
 * 4）@JmsListener注解的方法支持下列参数：javax.jms.Message 、org.springframework.messaging.Message 、javax.jms.Session和@Header、@Headers注解
 * 方法二：MessageListener
 * 1）共有三种：javax.jms.MessageListener、org.springframework.jms.listener.SessionAwareMessageListener、org.springframework.jms.listener.adapter.MessageListenerAdapter
 * 2）使用方法有三种：（1）MessageListener直接用MessageConsumer.setMessageListener即可
 *                 （2）MessageListener和SessionAwareMessageListener可以在onMessage方法上加注解@JmsListener
 *                 （3）三种的统一标准用法是
 */
package com.example.acitvemqspringbootdemo;

import org.apache.activemq.command.ActiveMQMessage;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import javax.jms.*;
import java.time.LocalTime;

@Component
public class Consumer {

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;
    @Autowired
    private JmsTemplate jmsTemplate;

    @JmsListener(destination = "${queue}" ,containerFactory = "jmsQueueListener")
    public void receive(Message msg) throws Exception {
        System.out.println("收到消息:" + ((TextMessage)msg).getText());
        if(msg.getJMSReplyTo()!=null)
            jmsMessagingTemplate.convertAndSend(msg.getJMSReplyTo(),"replying..."+msg.getJMSMessageID());
    }

    @JmsListener(destination = "myTopic",containerFactory = "jmsTopicListener")
    public void processMessage(String msg) {
        System.out.println("消费者1成功接收topic消息 :" + msg);
    }

    @JmsListener(destination = "send_receive_queue")
    public void consume(Message message) throws Exception {
        System.out.println("Received: " +((TextMessage)message).getText());
        jmsTemplate.send(message.getJMSReplyTo(), new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                Message responseMsg = session.createTextMessage("bar");
                responseMsg.setJMSCorrelationID(message.getJMSCorrelationID());
                return responseMsg;
            }
        });
    }



    @JmsListener(destination = "myTopic",containerFactory = "jmsTopicListener")
    public void handleMessage(String msg) {
        System.out.println("消费者2成功接收topic消息：" + msg);
    }

    @JmsListener(destination = "queue1", containerFactory = "jmsQueueListener")
    public void receiveQueue(final TextMessage text, Session session) throws JMSException {
        try {
            System.out.println("Consumer收到的报文为:" + text.getText());
            text.acknowledge();// 使用手动签收模式，需要手动的调用，如果不在catch中调用session.recover()消息只会在重启服务后重发
        } catch (Exception e) {
            session.recover();// 此不可省略 重发信息使用
        }
    }

    //事务，SessionAwareMessageListener在接收到消息后发送一个返回消息时也处于同一事务下
    @JmsListener(destination = "springTransactionQueue",containerFactory = "jmsTransactionListener")
    public void handleTransactionMessage(Message message,Session session) throws Exception{
        try {
            //会自动确认消息，无法实现手动确认
            System.out.println("[SpringTransaction]received：" + ((TextMessage)message).getText());
            throw new RuntimeException("测试异常是否回滚");  //模拟异常，消息仍然在队列中
        } catch (Exception e) {
            //手动回滚
            session.rollback();
            e.printStackTrace();
        }
    }

    //持久化
    @JmsListener(destination = "springDurableQueue")
    public void handleDurableMessage(Message message) {
        try {
            System.out.println("[SpringDurableQueue]received：" + ((TextMessage)message).getText());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @JmsListener(destination = "springDurableTopic",containerFactory = "topicContainerFactory1")
    public void receiveMessage1(Message message) throws Exception {
        System.out.println("[SpringDurableTopic1] received"+((TextMessage)message).getText());
    }

    @JmsListener(destination = "springDurableTopic",containerFactory = "topicContainerFactory2")
    public void receiveMessage2(Message message) throws Exception {
        System.out.println("[SpringDurableTopic2] received"+((TextMessage)message).getText());
    }

    //消息手动确认，需要在JmsListenerContainerFactory中关闭事务和设定消息确认方式（与发送端一致）
    @JmsListener(destination = "springAckQueue",containerFactory = "jmsAckListener")
    public void handleAckMessage(Message message,Session session) throws JMSException{
        try {
            String msg=((TextMessage)message).getText();

            System.out.println("[springAck]received：" + msg);
            if (msg.contains("3")) throw new JMSException("模拟出现异常......");
            //手动确认消息，否则消息会一直留在队列中
            message.acknowledge();
        } catch (JMSException e) {
            session.recover();
            e.printStackTrace();
        }
    }
    //接收消息，制造死信
    @JmsListener(destination = "springDeadQueue", containerFactory = "jmsTransactionListener")
    public void handleDeadMessage(String msg, Session session) {
        try {
            System.out.println("[Spring Dead]received：" + msg+"---"+ LocalTime.now());
            session.rollback();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //接收死信队列消息
    @JmsListener(destination = "ActiveMQ.DLQ", containerFactory = "jmsQueueListener")
    public void handleDeadQueueMessage(String msg) {
        try {
            System.out.println("[Spring Dead Queue]received：" + msg+"---"+ LocalTime.now());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //消息延迟接收，默认自带事务确认
    @JmsListener(destination = "springDelayQueue", containerFactory = "jmsQueueListener")
    public void handleDelayMessage(String msg) {
        try {
            System.out.println("[Spring Delay]received：" + msg+"---"+ LocalTime.now());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


